/**
 * packetgen.cpp
 * Generate a valid MAC frame for testing purposes.
 * 
 * @author David Winslow <cdw21@duke.edu>
 */


#include <iostream>
#include <stdlib.h> // for rand
#include <time.h>   // for seeding rand with the clock
#include <stdio.h>  // for printf

#define FRAMESIZE 1520
// maximum size for frame 
// (min size is 72; maybe we should avoid throwing away the rest of the memory?)

struct Frame
{ // general struct for representing a MAC Frame
  char* buff;
  int length;
  int capacity;
  
  Frame()
    : buff(new char[FRAMESIZE]), length(0), capacity(FRAMESIZE)
  {}
  
  void append(char byte)
  {
    if (length < capacity)
    {
      buff[length] = byte;
      length++;
    }
  }
  
  ~Frame()
  {
    delete buff;
  }
};

char randChar()
{
  return (char)(rand() & 0xFF);
}

void makeAddress(Frame& f)
{
  for (int i = 0; i < 6; i++)
  {
    f.append(randChar());
  }
}

/**
 * CRC Checking class heavily based on an online example.
 * @see http://www.relisoft.com/science/CrcNaive.html
 */
class CRC 
{
private:
  void checkBit(bool bit){
//     std::cout << bit? "1": "0";
    
    bool topBit = (myRegister & 0x80000000) != 0;
    // shift the bit into the register from the right
    myRegister <<= 1;
    myRegister ^= (bit ? 0x1:0x0);
    
    if (topBit)
    {
      // XOR the 32-bit key
      myRegister ^= myKey;
    }
  }
  
public:
  CRC(int key)
    : myKey(key), myRegister(0)
  {}
  
  int getResult()
  {
    int tmp = myRegister;
    myRegister = 0;
    return tmp;
  }
  
  void checkByte(unsigned char byte)
  {
    unsigned char mask = 0x80; // leftmost bit
    
    int byte_reordered = ((byte & 0xF0) >> 4) | ((byte & 0xF) << 4);
    //     std::cout << byte  << ":";
    
    for (int i = 0; i < 8; ++i){
      checkBit((byte_reordered & mask) != 0);
      mask >>= 1;
    }
  }
private:
  
  const int myKey;
  int myRegister;
};

int randomLength()
{
  // if less than 1536 decimal, this field indicates the number of data
  // octets in the data field. otherwise, it indicates the nature of the MAC
  // client protocol
  
  return 42 + rand() % (1500 - 42); // random value between 42 and 1500
}

int genCRC(Frame& f)
{
  CRC checker(0x04C11DB7); // from the IEEE 802.3 standard
  
  for (int i = 8; i < f.length; i++){ // skip the sync and frame-begin bytes
    checker.checkByte(f.buff[i]);
  }
  
  for (int i = 0; i < 4; i++) checker.checkByte(0);
  
  int result = checker.getResult();
  
  return result;
}

void printHex(char c){
  static char digits[] = 
  {'0', '1', '2', '3', '4', '5', '6', '7',
      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
  
  char upper = (c >> 4) & 0xF;
  char lower = c & 0xF;
  
  printf("%c%c", digits[upper], digits[lower]);
}

Frame buildFrame()
{
  Frame f;
  
  // preamble (7 bytes)
  for (int i = 0; i < 7; i++)
  {
    f.append(0xAA);
  }
  
  // SFD  (1 byte)
  f.append(0xAB);
  
  // destination address (6 bytes)
  makeAddress(f);
  
  // source address (6 bytes)
  makeAddress(f);
  
  // length/type (2 bytes)
  int length = randomLength();
  f.append((0xFF00 & length) >> 8);
  f.append(0xFF & length);
  
  std::cerr << length << std::endl;
  
  // client data (42-1500 bytes)
  for (int i = 0; i < length; i++)
  {
    f.append(randChar());
  }
  
  // pad ...
  // frame check 4
  int crc = genCRC(f);
  f.append((0xFF000000 & crc) >> 24);
  f.append((0xFF0000   & crc) >> 16);
  f.append((0xFF00     & crc) >> 8 );
  f.append(0xFF        & crc);
  
  return f;
}

void printMIF(Frame* theFrame){
	printf("#Autogenerated for ECE 251\n\n");
	printf("WIDTH=8;\n");
	printf("DEPTH=256;\n\n");
  printf("ADDRESS_RADIX=UNS;\n"); // addresses listed in unsigned decimal
  printf("DATA_RADIX=HEX;\n\n");    // values    listed in hexadecimal
	printf("CONTENT BEGIN\n");
	
	for (unsigned int index = 0; index < theFrame->length; index++){
		printf("\t%d\t:\t");
		printHex(theFrame->buff[index]);
		printf(";\n");
	}
	printf("END;\n"); 
}

void print(Frame* theFrame)
{
  static char digits[] = 
     {'0', '1', '2', '3', '4', '5', '6', '7',
      '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
  
  printf("getting ready to print \n");
  for (unsigned int index = 0; index < theFrame->length; index++){
    int nextGap = index + 8;
    nextGap = (nextGap < theFrame->length) ? nextGap : theFrame->length;
    
    for (index; index < nextGap; index++){
//       printf("value: %u  ", theFrame->buff[index]);
     
      printHex(theFrame->buff[index]);
    }
    
    printf("  ");
  }
}

void printVWF(Frame* theFrame){
  printf("/* Autogenerated for ECE 251 Group B */\n\n");
  printf("HEADER\n");
  printf("{\n");
  printf("  VERSION = 1;\n");
  printf("  TIME_UNIT = ns;\n");
  printf("  SIMULATION_TIME = 0.0;\n");
  printf("  GRID_PHASE = 0.0;\n");
  printf("  GRID_PERIOD = 10.0;\n");
  printf("  GRID_DUTY_CYCLE = 50;\n");
  printf("}\n\n");
  
  printf("SIGNAL(\"TEST_SIGNAL\")\n");
  printf("{\n");
  printf("  VALUE_TYPE = NINE_LEVEL_BIT;\n");
  printf("  SIGNAL_TYPE = BUS;\n");
  printf("  WIDTH = 4;\n");
  printf("  LSB_INDEX = 0;\n");
  printf("  DIRECTION = INPUT;\n");
  printf("  PARENT = \"\";\n");
  printf("}\n\n");
  
  for (int i = 0; i < 4; i++){
    printf("SIGNAL(\"TEST_SIGNAL[%d]\")\n", i);
    printf("{\n");
    printf("  VALUE_TYPE = NINE_LEVEL_BIT;\n");
    printf("  SIGNAL_TYPE = SINGLE_BIT;\n");
    printf("  WIDTH = 1;\n");
    printf("  LSB_INDEX = -1;\n");
    printf("  DIRECTION = INPUT;\n");
    printf("  PARENT = \"TEST_SIGNAL\";\n");
    printf("}\n");
  }
  
  for (int i = 0; i < 4; i++){
    printf("TRANSITION_LIST(\"TEST_SIGNAL[%d]\")\n", i);
    printf("{\n");
    printf("  NODE\n");
    printf("  {\n");
    printf("    REPEAT = 1;\n");
    for (int j = 0; j < theFrame->length; j++){
      printf("    LEVEL %d FOR 10.0;\n", ((theFrame->buff[j] >> (i+4)) & 1));
      printf("    LEVEL %d FOR 10.0;\n", ((theFrame->buff[j] >> i) & 1));
    }
    printf("  }\n");
    printf("}\n");
  }
  
  
  printf("DISPLAY_LINE\n");
  printf("{\n");
  printf("  CHANNEL = \"TEST_SIGNAL\";\n");
  printf("  EXPAND_STATUS = COLLAPSED;\n");
  printf("  RADIX = Hexadecimal;\n");
  printf("  TREE_INDEX = 0;\n");
  printf("  TREE_LEVEL = 0;\n");
  printf("  CHILDREN = 1, 2, 3, 4;\n");
  printf("}\n");
  
  for (int i = 0 ; i < 4; i++){
    printf("DISPLAY_LINE\n");
    printf("{\n");
    printf("  CHANNEL = \"TEST_SIGNAL[%d]\";\n", i);
    printf("  EXPAND_STATUS = COLLAPSED;\n");
    printf("  RADIX = Hexadecimal;\n");
    printf("  TREE_INDEX = %d;\n", i + 1);
    printf("  TREE_LEVEL = 1;\n");
    printf("  PARENT = 0;\n");
    printf("}\n");
  }
  
  printf("TIME_BAR\n");
  printf("{\n");
  printf("  TIME = 30000;\n");
  printf("  MASTER = TRUE;\n");
  printf("}\n");
  printf(";\n");
}

int main()
{
  srand(time(NULL));  
  
  Frame f = buildFrame();
//   printMIF(&f);
  printVWF(&f);
}
